import md5 from 'js-md5'

// eslint-disable-next-line @typescript-eslint/no-var-requires
const sm2 = require('sm-crypto').sm2

class RequestCryptoSM2 {

  constructor(publicKey, privateKey, strKey, cipherMode, debug) {
    this.publicKey = publicKey
    this.privateKey = privateKey
    this.strKey = strKey
    this.cipherMode = cipherMode
    this.debug = debug
  }

  // 随机数
  _randomString (length, charSet) {
    let text = ''
    const chars = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
    for (let i = 0; i < length; i++) {
      const randomPoz = Math.floor(Math.random() * chars.length)
      text += chars.substring(randomPoz, randomPoz + 1)
    }
    return text
  }

  // 转毫秒时间戳
  _formatTimeStamp () {
    return (new Date()).valueOf()
  }

  // 自然字典排序
  _sortJsonByKeys (data) {
    // console.log(data)
    const arr = []
    const res = Object.keys(data).sort()
    for (const key in res) {
      const value = data[res[key]] 
      if (value || value === '' || value === 0 || value === false) {
        if (typeof(value) === 'object') {
          arr.push(JSON.stringify(value))
        } else {
          arr.push(value)
        }
      }
    }
    if (this.debug) console.log('sm2====arr.join', arr.join('-'))
    return arr.join('-')
  }

  // 简单对象 判断为空删除
  _deleteEmptyProperty (data) {
    for (const item in data) {
      const value = data[item]
      if (value === null || value === undefined) {
        delete data[item]
      }
    }
    return data
  }

  // 添加时间戳和16位随机数
  _coverData (data) {
    const params = this._deleteEmptyProperty(data)
    const obj = {
      timestemp: this._formatTimeStamp(), // 毫秒时间戳
      notice: this._randomString(16), // 16位随机数
      ...params
    }
    return obj
  }

  // 签名加密
  _cryptoSign (obj) {
    const strResult = this._sortJsonByKeys(obj) + this.strKey
    const sign = md5(strResult)
    return sign
  }

  // 对data进行sm2加密
  _cryptoData (obj) {
    return sm2.doEncrypt(JSON.stringify(obj), this.publicKey, this.cipherMode)
  }

  //加密返回data与sign
  encryptResult (data) {
    if (this.debug) console.log('sm2====data', data)
    const obj = this._coverData(data)
    if (this.debug) console.log('sm2====obj', obj)
    return {
      params: this._cryptoData(obj),
      sign: this._cryptoSign(obj)
    }
  }

  // 解密
  decryptResult (data) {
    if (data) {
      const result = sm2.doDecrypt(data, this.privateKey, this.cipherMode)
      if (this.debug) console.log('sm2====result', result)
      return result
    } else {
      console.error('data is not find')
    }
  }

}

export default RequestCryptoSM2